


#include "net.h"



#define __in_range(c, lo, up)  ((qe_u8)(c) >= (lo) && (qe_u8)(c) <= (up))
#define _isdigit(c)           __in_range((c), '0', '9')
#define _isxdigit(c)          (_isdigit(c) || __in_range((c), 'a', 'f') || __in_range((c), 'A', 'F'))
#define __islower(c)           __in_range((c), 'a', 'z')
#define __isspace(c)           ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\v')



static int hex2num(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    if (c >= 'a' && c<= 'f')
        return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    return -1;
}

qe_u32 ip4addr_aton(const char *cp)
{
    char c;
    qe_u32 val;
    qe_u8 base;
  
    qe_u32 parts[4];
    qe_u32 *pp = parts;

    c = *cp;
    for (;;) {
        /*
          * Collect number up to ``.''.
          * Values are specified as for C:
          * 0x=hex, 0=octal, 1-9=decimal.
          */
        if (!_isdigit(c)) {
            return 0;
        }
        val = 0;
        base = 10;
        if (c == '0') {
            c = *++cp;
            if (c == 'x' || c == 'X') {
                base = 16;
                c = *++cp;
            } else {
                base = 8;
            }
        }
        for (;;) {
            if (_isdigit(c)) {
                val = (val * base) + (qe_u32)(c - '0');
                c = *++cp;
            } else if (base == 16 && _isxdigit(c)) {
                val = (val << 4) | (qe_u32)(c + 10 - (__islower(c) ? 'a' : 'A'));
                c = *++cp;
            } else {
                break;
            }
        }
        if (c == '.') {
            /*
               * Internet format:
               *  a.b.c.d
               *  a.b.c   (with c treated as 16 bits)
               *  a.b (with b treated as 24 bits)
               */
            if (pp >= parts + 3) {
                return 0;
            }
            *pp++ = val;
            c = *++cp;
        } else {
            break;
        }
    }
      /*
       * Check for trailing characters.
       */
    if (c != '\0' && !__isspace(c)) {
        return 0;
    }
    /*
     * Concoct the address according to
     * the number of parts specified.
     */
    switch (pp - parts + 1) {

    case 0:
        return 0;       /* initial nondigit */

    case 1:             /* a -- 32 bits */
        break;

    case 2:             /* a.b -- 8.24 bits */
        if (val > 0xffffffUL) {
            return 0;
        }
        if (parts[0] > 0xff) {
            return 0;
        }
        val |= parts[0] << 24;
        break;

    case 3:             /* a.b.c -- 8.8.16 bits */
        if (val > 0xffff) {
            return 0;
        }
        if ((parts[0] > 0xff) || (parts[1] > 0xff)) {
            return 0;
        }
        val |= (parts[0] << 24) | (parts[1] << 16);
        break;

    case 4:             /* a.b.c.d -- 8.8.8.8 bits */
        if (val > 0xff) {
            return 0;
        }
        if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) {
            return 0;
        }
        val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
        break;
    default:
        net_err("unhandled");
        break;
    }

    return qe_htonl(val);
}

qe_bool ipaddr_valid(char *ipaddr_str)
{
    int num = 0;
    char *p = ipaddr_str;

    while (*p != '\0') {

        if (*p == ' ' || *p<'0' || *p>'9') {
            return qe_false;
        }

        int sum = 0;

        while (*p != '.' && *p != '\0') {
            if (*p == ' ' || *p<'0' || *p>'9') {
                return qe_false;
            }
            sum = sum*10 + *p-48;
            p++;
        }

        if (*p == '.') {
            if ((*(p-1) >= '0' && *(p-1) <= '9') && (*(p+1) >= '0' && *(p+1) <= '9')) {
                num++;
            } else {
                return qe_false;
            }
        }
        
        if ((sum > 255) || num>3) {
            return qe_false;
        }

        if (*p != '\0') p++;
    }

    if (num != 3) return qe_false;
    return qe_true;
}

qe_bool netmask_valid(char *netmask)
{
    qe_u32 mask;
    
    if (ipaddr_valid(netmask)) {
        mask = ip4addr_aton(netmask);
        if (((mask+1) & (mask)) == 0)
            return qe_true;
    }

    return qe_false;
}

void macaddr_aton(const char *p, qe_u8 *mac)
{
    int i = 0;

    while (i<6) {
        if (' ' == *p || ':' == *p || '"' == *p || '\'' == *p) {
            p++;
            continue;
        }
        *(mac+i) = ((hex2num(*p)<<4)|hex2num(*(p+1)));
        i++;
        p += 2;
    }
}